#include "rtc.h"

struct time_st mytime;

// 设置时间 将参数的时间结构体转化为时间戳写入RTC_CNT 32位寄存器
void set_time(const struct time_st *tm);

// 转换时间
void conver_time(struct time_st *tm);

void RTC_IRQHandler(void)
{
	// 当秒中断产生则调用此函数
	// 读RTC_CNT值转换为时间结构体
	if (RTC_GetITStatus(RTC_IT_SEC) == SET) {
		// 秒中断触发
		conver_time(&mytime);
		// 已经响应此终端，清除这一位
		RTC_ClearITPendingBit(RTC_IT_SEC);
	}
}

static void NVIC_Configuration()
{
	NVIC_InitTypeDef nvic_value;
	
	// 优先级配比
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	nvic_value.NVIC_IRQChannel = RTC_IRQn;// 分别中断号
	nvic_value.NVIC_IRQChannelCmd = ENABLE;
	nvic_value.NVIC_IRQChannelPreemptionPriority = 2;
	nvic_value.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&nvic_value);
	
	// 配置闹钟中断
}

static void RTC_Configuration(const struct time_st *tm)
{
	/* Enable PWR and BKP clocks 如果需要修改RTC备份寄存器，
	必须使能RCC_APB1ENR的?PWREN BKPEN
	PWR_CR DBP
	*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

	 /* Allow access to BKP Domain 开启写访问*/
	PWR_BackupAccessCmd(ENABLE);

	/* Reset Backup Domain 重启备份值寄存器*/
	BKP_DeInit();

	/* Enable LSE 外部低速时钟为RTC供频,所以需要使能*/
	RCC_LSEConfig(RCC_LSE_ON);
	/* Wait till LSE is ready 等待LSE稳定*/
	while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
	{}

	/* Select LSE as RTC Clock Source LSE作为RTC时钟源*/
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

	/* Enable RTC Clock 使能RTC*/
	RCC_RTCCLKCmd(ENABLE);

	/* Wait for RTC registers synchronization 等待寄存器值同步*/
	RTC_WaitForSynchro();

	/* Wait until last write operation on RTC registers has finished */
	RTC_WaitForLastTask();

	/* Enable the RTC Second 使能秒中断*/
	RTC_ITConfig(RTC_IT_SEC, ENABLE);
	// 闹钟中断中断触发

	/* Wait until last write operation on RTC registers has finished */
	RTC_WaitForLastTask();

	// 进入配置模式
	RTC_EnterConfigMode();
	 
	/* Set RTC prescaler: set RTC period to 1sec */
	RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

	/* Wait until last write operation on RTC registers has finished */
	RTC_WaitForLastTask();

	// 写入时间
	set_time(tm);
	/* Wait until last write operation on RTC registers has finished */
	RTC_WaitForLastTask();

	// 退出配置模式
	RTC_ExitConfigMode();
	
}

void rtc_init(const struct time_st *tm)
{
	// 初始化中断控制器
	NVIC_Configuration();
	
	// 判断RTC是否为第一次驱动，如果是需要配置RTC
	// BKP_DR1备份值寄存器，第一次驱动应该是没有值的 0xA5A5就是事例
	if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A6) {
		RTC_Configuration(tm); // 配置RTC
		// 写入所判断的值,来确保不是第一次驱动则不必要重复config
		BKP_WriteBackupRegister(BKP_DR1, 0xA5A6);
	} else {
		// 寄存器值同步
		RTC_WaitForSynchro();
		// 使能秒中断
		RTC_ITConfig(RTC_IT_SEC, ENABLE);
		// 保证上一次rtc写操作完成
		RTC_WaitForLastTask();
	}
	
}

void get_time(struct time_st *tm)
{
	*tm = mytime;
}

static int year_is_leap(int year)
{
	return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

void conver_time(struct time_st *tm)
{
	int secCount;
	int days;
	int hms; // 时分秒
	int tmp;
	int i;
	int monthdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	// 读出来计数值 转换为时间结构体
	secCount = RTC_GetCounter();
	days = secCount / (24 * 60 * 60);
	// 星期几 1970/1/1是星期四
	tm->week = (days + 4) % 7;
	
	hms = secCount % (24 * 60 * 60);
	// days--->year month day
	tmp = 1970;
	while (days >= 365) {
		// 可能够一年
		if (year_is_leap(tmp)) {
			if (days < 366)
				break;
			days -= 366;
		} else {
			// 平年
			days -= 365;
		}
		tmp++;
	}
	// day已经小于365 还有可能是接下来是闰年但是days<366
	tm->year = tmp;
	// days剩下月份和日期
	for (i = 1; i <= 12; i++) {
		if (i == 2 && year_is_leap(tmp)) { // 二月
			monthdays[i] ++;
		}
		if (days < monthdays[i])
			break;
		else 
			days -= monthdays[i];
	}
	tm->month = i;
	tm->day = days + 1;
	// hms--->hour minute second
	tm->hour = hms / (60 * 60);
	tm->minute = (hms - tm->hour * 60 * 60) / 60;
	tm->second = (hms - tm->hour * 60 * 60 - tm->minute * 60);
}


void set_time(const struct time_st *tm)
{
	int secCount = 0;
	int i;
	int monthdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	
	// 基础元年1970.1.1 00:00:00
	// 将tm时间结构体转换为时间戳
	for (i = 1970; i < tm->year; i ++) {
		if (year_is_leap(i)) {
			secCount += 366 * 24 * 60 * 60;
		} else {
			secCount += 365 * 24 * 60 * 60;
		}
	}
	// month
	for (i = 0; i < tm->month; i++) {
		secCount += monthdays[i] * 24 * 60 * 60;
		if (i == 2) {
			// 如果是二月
			if (year_is_leap(tm->year))
				secCount += 24 * 60 * 60;
		}
	}
	// day
	secCount += (tm->day - 1) * 24 * 60 * 60;
	// hour
	secCount += tm->hour * 60 * 60;
	// minute
	secCount += tm->minute * 60;
	// second
	secCount += tm->second;

	/* Enable PWR and BKP clocks 如果需要修改RTC备份寄存器，
	必须使能RCC_APB1ENR的?PWREN BKPEN
	PWR_CR DBP
	*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	 /* Allow access to BKP Domain 开启写访问*/
	PWR_BackupAccessCmd(ENABLE);
	// 设置计数值
	RTC_SetCounter(secCount);
	// 保证上一次rtc写操作完成
	RTC_WaitForLastTask();
}

void RTCAlarm_IRQHandler(void)
{


}



